
package at.fhj.ase.clientarch.client.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.fhj.ase.clientarch.client.sigar.GraphData;
import at.fhj.ase.clientarch.common.HardwareData;
import at.fhj.ase.clientarch.common.exception.BizException;
import at.fhj.ase.clientarch.common.util.CommonUtil;
import at.fhj.ase.clientarch.common.util.WindowUtil;
import de.progra.charting.DefaultChart;
import de.progra.charting.event.ChartDataModelEvent;
import de.progra.charting.event.ChartDataModelListener;
import de.progra.charting.model.EditableChartDataModel;
import de.progra.charting.render.LineChartRenderer;
import de.progra.charting.swing.ChartPanel;

/**
 * @author cja, sfe | www.fh-joanneum.at | Client Architectures and Design
 */
public final class MainFrame extends JFrame implements ActionListener, ChartDataModelListener {
  private class RefreshTimerTask extends TimerTask {
    @Override
    public void run() {
      fetchCurrentDataFromServer();
    }
  }

  private final Logger logger = LoggerFactory.getLogger(getClass().getName());

  private static final long serialVersionUID = 6867319825736506085L;

  private javax.swing.JButton jBtnExportCSV;
  private javax.swing.JLabel jLabelIP;
  private javax.swing.JLabel jLabelIPHeadline;
  private javax.swing.JLabel jLabelPort;
  private javax.swing.JLabel jLabelPortHeadline;
  private javax.swing.JLabel jLabelcurrentCPU;
  private javax.swing.JLabel jLabelcurrentCPUHeadline;
  private javax.swing.JLabel jLabelcurrentRAM;
  private javax.swing.JLabel jLabelcurrentRAMHeadline;
  private javax.swing.JPanel jPanelServerInfo;
  private javax.swing.JPanel jPanelCurrentValues;
  private ChartPanel serverChartPanel;
  private EditableChartDataModel data;
  private double time = 3.0;

  // XXX also used by ExportGUI.java => should it be static?
  public static final String ACTION_CMD_EXPORT = "actionCmdExport";

  MainFrame() throws ClassNotFoundException, SQLException {
    initGUIComponents();
    startTimer();
  }

  private void startTimer() {
    new Timer(true).scheduleAtFixedRate(new RefreshTimerTask(), 0, ClientController.INSTANCE.getTimerInvertal());
  }

  private synchronized void fetchCurrentDataFromServer() {
    try {
      // the first element will never be null as the server at least returns a dummy object in case of problems
      final int FIRST = 0;
      final HardwareData hardwareData = ClientController.INSTANCE.getHwComponent().getCurrentData().getDataList().get(FIRST);

      // paint new values in chart
      data.insertValue(0, Double.valueOf(hardwareData.getCpu()), Double.valueOf(time));
      data.insertValue(1, Double.valueOf(hardwareData.getRam()), Double.valueOf(time));

      jLabelcurrentCPU.setText((int) hardwareData.getCpu() + "%");
      jLabelcurrentRAM.setText((int) hardwareData.getRam() + "%");

      time++;
    } catch (RemoteException re) {
      logger.error("Could not fetch current hardware data from server due to connection problems: ", re);
    } catch (BizException be) {
      logger.error("Troubles fetching hardware data: ", be);
    }
  }

  private void initGUIComponents() throws ClassNotFoundException, SQLException {
    jPanelServerInfo = new javax.swing.JPanel();
    jLabelIPHeadline = new javax.swing.JLabel();
    jLabelPortHeadline = new javax.swing.JLabel();
    jLabelIP = new javax.swing.JLabel();
    jLabelPort = new javax.swing.JLabel();

    jPanelCurrentValues = new javax.swing.JPanel();
    jLabelcurrentCPU = new javax.swing.JLabel();
    jLabelcurrentCPUHeadline = new javax.swing.JLabel();
    jLabelcurrentRAM = new javax.swing.JLabel();
    jLabelcurrentRAMHeadline = new javax.swing.JLabel();

    jBtnExportCSV = new javax.swing.JButton();

    jBtnExportCSV.addActionListener(this);
    jBtnExportCSV.setActionCommand(ACTION_CMD_EXPORT);

    // Create an editable chart data model
    GraphData initialGraphData = GraphData.INSTANCE;
    data = new EditableChartDataModel(initialGraphData.getDataSetValues(), initialGraphData.getTimeLine(), initialGraphData.getDataSetTitles());
    data.setAutoScale(true);
    // Creating the Swing ChartPanel instead of DefaultChart
    serverChartPanel = new ChartPanel(data, initialGraphData.getTitle(), DefaultChart.LINEAR_X_LINEAR_Y);
    // Adding ChartRenderer as usual
    serverChartPanel.addChartRenderer(new LineChartRenderer(serverChartPanel.getCoordSystem(), data), 1);
    // Register EventListener
    data.addChartDataModelListener(this);
    serverChartPanel.getCoordSystem().setXAxisUnit("t");
    serverChartPanel.getCoordSystem().setYAxisUnit("%");

    this.setName("jFrameMain");
    this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); // needed for window listener
    this.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosed(WindowEvent e) {
        super.windowClosed(e); // nonsense cause abstract, but keep inheritance tree
        logger.info("Shutting down application...");
        System.exit(0); // shut down the virtual machine brutally (for now)
      }
    });

    jPanelCurrentValues.setBorder(javax.swing.BorderFactory.createTitledBorder("Current Values"));
    jPanelCurrentValues.setName("jPanelCurrentValues");

    jLabelcurrentCPUHeadline.setText("CPU: ");
    jLabelcurrentCPUHeadline.setName("jLabelCurrentCPUHeadline");

    jLabelcurrentCPU.setText("50%");
    jLabelcurrentCPU.setName("jLabelCurrentCPU");

    jLabelcurrentRAMHeadline.setText("RAM: ");
    jLabelcurrentRAMHeadline.setName("jLabelCurrentRAMHeadline");

    jLabelcurrentRAM.setText("20%");
    jLabelcurrentRAM.setName("jLabelCurrentRAM");

    javax.swing.GroupLayout jPanelCurrentValuesLayout = new javax.swing.GroupLayout(jPanelCurrentValues);
    jPanelCurrentValues.setLayout(jPanelCurrentValuesLayout);
    jPanelCurrentValuesLayout
                             .setHorizontalGroup(jPanelCurrentValuesLayout
                                                                          .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                                          .addGroup(
                                                                                    jPanelCurrentValuesLayout
                                                                                                             .createSequentialGroup()
                                                                                                             .addGroup(
                                                                                                                       jPanelCurrentValuesLayout
                                                                                                                                                .createParallelGroup(
                                                                                                                                                                     javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                                                                .addComponent(
                                                                                                                                                              jLabelcurrentCPUHeadline)

                                                                                                                                                .addComponent(
                                                                                                                                                              jLabelcurrentRAMHeadline))
                                                                                                             .addPreferredGap(
                                                                                                                              javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                                                                                             .addGroup(
                                                                                                                       jPanelCurrentValuesLayout
                                                                                                                                                .createParallelGroup(
                                                                                                                                                                     javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                                                                .addGroup(
                                                                                                                                                          jPanelCurrentValuesLayout
                                                                                                                                                                                   .createSequentialGroup()
                                                                                                                                                                                   .addComponent(
                                                                                                                                                                                                 jLabelcurrentRAM)
                                                                                                                                                                                   .addGap(
                                                                                                                                                                                           8,
                                                                                                                                                                                           8,
                                                                                                                                                                                           8))
                                                                                                                                                .addGroup(
                                                                                                                                                          jPanelCurrentValuesLayout
                                                                                                                                                                                   .createSequentialGroup()
                                                                                                                                                                                   .addComponent(
                                                                                                                                                                                                 jLabelcurrentCPU,
                                                                                                                                                                                                 javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                                                                                                 82,
                                                                                                                                                                                                 Short.MAX_VALUE)
                                                                                                                                                                                   .addContainerGap(
                                                                                                                                                                                                    20,
                                                                                                                                                                                                    javax.swing.GroupLayout.PREFERRED_SIZE)))));
    jPanelCurrentValuesLayout
                             .setVerticalGroup(jPanelCurrentValuesLayout
                                                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                                        .addGroup(
                                                                                  jPanelCurrentValuesLayout
                                                                                                           .createSequentialGroup()
                                                                                                           .addGroup(
                                                                                                                     jPanelCurrentValuesLayout
                                                                                                                                              .createParallelGroup(
                                                                                                                                                                   javax.swing.GroupLayout.Alignment.BASELINE)
                                                                                                                                              .addComponent(
                                                                                                                                                            jLabelcurrentCPUHeadline)
                                                                                                                                              .addComponent(
                                                                                                                                                            jLabelcurrentCPU))
                                                                                                           .addPreferredGap(
                                                                                                                            javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                                                                           .addGroup(
                                                                                                                     jPanelCurrentValuesLayout
                                                                                                                                              .createParallelGroup(
                                                                                                                                                                   javax.swing.GroupLayout.Alignment.BASELINE)
                                                                                                                                              .addComponent(
                                                                                                                                                            jLabelcurrentRAMHeadline)
                                                                                                                                              .addComponent(
                                                                                                                                                            jLabelcurrentRAM))));

    // Panel Server Information
    jPanelServerInfo.setBorder(javax.swing.BorderFactory.createTitledBorder("Server Information"));
    jPanelServerInfo.setName("jPanelServerInfo");

    jLabelIPHeadline.setText("IP Address:");
    jLabelIPHeadline.setName("jLabelIPHeadline");

    jLabelPortHeadline.setText("Port:");
    jLabelPortHeadline.setName("jLabelPortHeadline");

    // get server IP
    jLabelIP.setText("localhost");
    jLabelIP.setName("jLabelIP");

    // get server port
    jLabelPort.setText("" + CommonUtil.RMI_PORT);
    jLabelPort.setName("jLabelPort");

    javax.swing.GroupLayout jPanelServerInfoLayout = new javax.swing.GroupLayout(jPanelServerInfo);
    jPanelServerInfo.setLayout(jPanelServerInfoLayout);
    jPanelServerInfoLayout
                          .setHorizontalGroup(jPanelServerInfoLayout
                                                                    .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                                    .addGroup(
                                                                              jPanelServerInfoLayout
                                                                                                    .createSequentialGroup()
                                                                                                    .addGroup(
                                                                                                              jPanelServerInfoLayout
                                                                                                                                    .createParallelGroup(
                                                                                                                                                         javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                                                    .addComponent(
                                                                                                                                                  jLabelIPHeadline)

                                                                                                                                    .addComponent(
                                                                                                                                                  jLabelPortHeadline))
                                                                                                    .addPreferredGap(
                                                                                                                     javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                                                                                    .addGroup(
                                                                                                              jPanelServerInfoLayout
                                                                                                                                    .createParallelGroup(
                                                                                                                                                         javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                                                    .addGroup(
                                                                                                                                              jPanelServerInfoLayout
                                                                                                                                                                    .createSequentialGroup()
                                                                                                                                                                    .addComponent(
                                                                                                                                                                                  jLabelPort)
                                                                                                                                                                    .addGap(
                                                                                                                                                                            8,
                                                                                                                                                                            8,
                                                                                                                                                                            8))
                                                                                                                                    .addGroup(
                                                                                                                                              jPanelServerInfoLayout
                                                                                                                                                                    .createSequentialGroup()
                                                                                                                                                                    .addComponent(
                                                                                                                                                                                  jLabelIP,
                                                                                                                                                                                  javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                                                                                  82,
                                                                                                                                                                                  Short.MAX_VALUE)
                                                                                                                                                                    .addContainerGap(
                                                                                                                                                                                     20,
                                                                                                                                                                                     javax.swing.GroupLayout.PREFERRED_SIZE)))));
    jPanelServerInfoLayout
                          .setVerticalGroup(jPanelServerInfoLayout
                                                                  .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                                  .addGroup(
                                                                            jPanelServerInfoLayout
                                                                                                  .createSequentialGroup()
                                                                                                  .addGroup(
                                                                                                            jPanelServerInfoLayout
                                                                                                                                  .createParallelGroup(
                                                                                                                                                       javax.swing.GroupLayout.Alignment.BASELINE)
                                                                                                                                  .addComponent(
                                                                                                                                                jLabelIPHeadline)
                                                                                                                                  .addComponent(jLabelIP))
                                                                                                  .addPreferredGap(
                                                                                                                   javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                                                                  .addGroup(
                                                                                                            jPanelServerInfoLayout
                                                                                                                                  .createParallelGroup(
                                                                                                                                                       javax.swing.GroupLayout.Alignment.BASELINE)
                                                                                                                                  .addComponent(
                                                                                                                                                jLabelPortHeadline)
                                                                                                                                  .addComponent(jLabelPort))));

    javax.swing.GroupLayout jPanelStatisticsLayout = new javax.swing.GroupLayout(serverChartPanel);
    serverChartPanel.setLayout(jPanelStatisticsLayout);
    jPanelStatisticsLayout.setHorizontalGroup(jPanelStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 0,
                                                                                                                                           Short.MAX_VALUE));
    jPanelStatisticsLayout
                          .setVerticalGroup(jPanelStatisticsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 0, Short.MAX_VALUE));

    jPanelStatisticsLayout
                          .setVerticalGroup(jPanelServerInfoLayout
                                                                  .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                                  .addGroup(
                                                                            jPanelServerInfoLayout
                                                                                                  .createSequentialGroup()
                                                                                                  .addGroup(
                                                                                                            jPanelServerInfoLayout
                                                                                                                                  .createParallelGroup(
                                                                                                                                                       javax.swing.GroupLayout.Alignment.BASELINE)
                                                                                                                                  .addComponent(jLabelIP))));

    jBtnExportCSV.setText("Export to CSV file");
    jBtnExportCSV.setName("jBtnExportCSV");

    javax.swing.GroupLayout jFrameMainLayout = new javax.swing.GroupLayout(this.getContentPane());
    this.getContentPane().setLayout(jFrameMainLayout);
    jFrameMainLayout
                    .setHorizontalGroup(jFrameMainLayout
                                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                        .addGroup(
                                                                  javax.swing.GroupLayout.Alignment.TRAILING,
                                                                  jFrameMainLayout
                                                                                  .createSequentialGroup()
                                                                                  .addContainerGap()
                                                                                  .addGroup(
                                                                                            jFrameMainLayout
                                                                                                            .createParallelGroup(
                                                                                                                                 javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                            .addComponent(jPanelCurrentValues,
                                                                                                                          javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                          javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                          Short.MAX_VALUE)
                                                                                                            .addComponent(jPanelServerInfo,
                                                                                                                          javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                          javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                          Short.MAX_VALUE))
                                                                                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                                                  .addGroup(
                                                                                            jFrameMainLayout
                                                                                                            .createParallelGroup(
                                                                                                                                 javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                            .addComponent(jBtnExportCSV)
                                                                                                            .addComponent(serverChartPanel, 280, 374, 900))
                                                                                  .addContainerGap()));
    jFrameMainLayout
                    .setVerticalGroup(jFrameMainLayout
                                                      .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                      .addGroup(
                                                                javax.swing.GroupLayout.Alignment.TRAILING,
                                                                jFrameMainLayout
                                                                                .createSequentialGroup()
                                                                                .addContainerGap()
                                                                                .addGroup(
                                                                                          jFrameMainLayout
                                                                                                          .createParallelGroup(
                                                                                                                               javax.swing.GroupLayout.Alignment.LEADING)
                                                                                                          .addGroup(
                                                                                                                    jFrameMainLayout
                                                                                                                                    .createSequentialGroup()
                                                                                                                                    .addComponent(
                                                                                                                                                  jPanelCurrentValues,
                                                                                                                                                  javax.swing.GroupLayout.PREFERRED_SIZE,
                                                                                                                                                  javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                                                  javax.swing.GroupLayout.PREFERRED_SIZE)
                                                                                                                                    .addPreferredGap(
                                                                                                                                                     javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                                                                                                                                     18,
                                                                                                                                                     Short.MAX_VALUE)
                                                                                                                                    .addGap(18, 18, 18)
                                                                                                                                    .addComponent(
                                                                                                                                                  jPanelServerInfo,
                                                                                                                                                  javax.swing.GroupLayout.PREFERRED_SIZE,
                                                                                                                                                  javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                                                                                                  javax.swing.GroupLayout.PREFERRED_SIZE)
                                                                                                                                    .addGap(9, 9, 9))
                                                                                                          .addComponent(serverChartPanel, 280, 374, 900))
                                                                                .addGap(18, 18, 18).addComponent(jBtnExportCSV).addGap(18, 18, 18)
                                                                                .addContainerGap()));

  }

  @Override
  public void actionPerformed(ActionEvent e) {
    final String actionCommand = e.getActionCommand();
    if (actionCommand.equals(ACTION_CMD_EXPORT)) {
      onExportStartExportDialog();
    }
  }

  private void onExportStartExportDialog() {
    final ExportDialog exportGUI = new ExportDialog(this);
    exportGUI.setSize(500, 150);
    WindowUtil.centerWindow(exportGUI);
    exportGUI.setVisible(true);
  }

  public void chartDataChanged(ChartDataModelEvent evt) {
    // The DataModel changed -> update display
    serverChartPanel.revalidate();
    repaint();
  }

  List<HardwareData> getCurrentChartData() {
    final List<HardwareData> dataList = new ArrayList<HardwareData>();
    final int COLUMN_CPU = 0;
    final int COLUMN_RAM = 1;

    //XXX why is the database number not 1?
    for (int i = 0; i < data.getDataSetLength(0); i++) {
      // each row contains 2 columns
      dataList.add(new HardwareData(data.getValueAt(COLUMN_CPU, i).doubleValue(), data.getValueAt(COLUMN_RAM, i).doubleValue(), null));
    }

    return dataList;
  }
}